package org.example.config;


import lombok.SneakyThrows;
import org.example.filter.PhoneAuthenticationFilter;
import org.example.filter.TokenAuthorizationFilter;
import org.example.filter.UserAuthenticationFilter;
import org.example.filter.WeChatAuthenticationFilter;
import org.example.handler.LoginFailureHandler;
import org.example.handler.LoginSuccessHandler;
import org.example.handler.MyAuthExceptionEntryPoint;
import org.example.util.JwtUtils;
import org.example.validate.PhoneTokenAuthenticationProvider;
import org.example.validate.TokenAuthenticationConverter;
import org.example.validate.UsernameAuthenticationProvider;
import org.example.validate.WeChatAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private TokenAuthenticationConverter tokenAuthenticationConverter;

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;

    @Autowired
    private PhoneTokenAuthenticationProvider phoneTokenAuthenticationProvider;

    @Autowired
    private UsernameAuthenticationProvider usernameAuthenticationProvider;

    @Autowired
    private WeChatAuthenticationProvider weChatAuthenticationProvider;

    @Autowired
    private JwtUtils jwtUtils;

//    @Autowired
//    private SecurityProperties securityProperties;


    /**
     * 静态资源 放行
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().mvcMatchers(
                "/index.html",
                "/swagger**/**",
                "/v3/**",
                "/webjars/**"
        );
    }


    @Override
    @SneakyThrows
    protected void configure(HttpSecurity http) {
        http
                .cors()//允许跨域资源共享
                .and()
                .csrf().disable()//跨站请求检查
                .exceptionHandling() // 异常处理设置，因为登录是在filter中执行，比请求到controller早，ControllerAdvice只能捕获controller
                .authenticationEntryPoint(new MyAuthExceptionEntryPoint())//自行处理
                .and()
                .authorizeRequests()
                .antMatchers("/user/getPhoneCode","/user/register","/test/**",
                        PhoneAuthenticationFilter.SPRING_SECURITY_RESTFUL_LOGIN_URL,
                        UserAuthenticationFilter.SPRING_SECURITY_RESTFUL_LOGIN_URL,
                        WeChatAuthenticationFilter.SPRING_SECURITY_RESTFUL_LOGIN_URL)
                .permitAll()
                .anyRequest().authenticated()//其他请求都需要登录认证
                .and()
                .addFilterBefore(weChatAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(phoneAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(userAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(tokenAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);//不使用session

    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(usernameAuthenticationProvider);
        auth.authenticationProvider(phoneTokenAuthenticationProvider);
        auth.authenticationProvider(weChatAuthenticationProvider);

    }

//    @Bean
//    public DaoAuthenticationProvider daoAuthenticationProvider(){
//        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//        daoAuthenticationProvider.setUserDetailsService(domainUserDetailsService);
//        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
//        return daoAuthenticationProvider;
//    }


    @Bean
    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
        return NoOpPasswordEncoder.getInstance();
    }


    @Override
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Bean
    public PhoneAuthenticationFilter phoneAuthenticationFilter() throws Exception {
        PhoneAuthenticationFilter phoneAuthenticationFilter = new PhoneAuthenticationFilter();
        phoneAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        phoneAuthenticationFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
        phoneAuthenticationFilter.setAuthenticationFailureHandler(loginFailureHandler);
        return phoneAuthenticationFilter;
    }

    @Bean
    public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
        UserAuthenticationFilter userAuthenticationFilter = new UserAuthenticationFilter();
        userAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        userAuthenticationFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
        userAuthenticationFilter.setAuthenticationFailureHandler(loginFailureHandler);
        return userAuthenticationFilter;
    }

    @Bean
    public WeChatAuthenticationFilter weChatAuthenticationFilter() throws Exception {
        WeChatAuthenticationFilter weChatAuthenticationFilter = new WeChatAuthenticationFilter();
        weChatAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        weChatAuthenticationFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
        weChatAuthenticationFilter.setAuthenticationFailureHandler(loginFailureHandler);
        return weChatAuthenticationFilter;
    }

    @Bean
    public TokenAuthorizationFilter tokenAuthorizationFilter() throws Exception{
        TokenAuthorizationFilter tokenAuthorizationFilter = new TokenAuthorizationFilter(authenticationManagerBean());
        tokenAuthorizationFilter.setJwtUtils(jwtUtils);
//        tokenAuthorizationFilter.setProperties(securityProperties);
        tokenAuthorizationFilter.setTokenAuthenticationConverter(tokenAuthenticationConverter);
        return  tokenAuthorizationFilter;
    }
}
